package com.szcinda.call.service;

import com.szcinda.call.ExceptionDto;
import com.szcinda.call.sms.SendSms;
import lombok.Data;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.io.Serializable;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

@Component
public class ExceptionContext {

    @Value("${admin.phone}")
    private String adminPhone;

    private final ConcurrentHashMap<String, String> exceptionStrMap = new ConcurrentHashMap<>();

    private final ConcurrentHashMap<String, String> robotNoHeartBreakMap = new ConcurrentHashMap<>();


    private final ConcurrentHashMap<String, AlarmNotice> alarmNoticeMap1 = new ConcurrentHashMap<>();
    private final ConcurrentHashMap<String, AlarmNotice> alarmNoticeMap2 = new ConcurrentHashMap<>();

    private final ConcurrentHashMap<HeartBreakData, LocalDateTime> heartBreakConcurrentHashMap = new ConcurrentHashMap<>();


    public void refresh(HeartBreakData data) {
        heartBreakConcurrentHashMap.put(data, LocalDateTime.now());
    }

    public void removeBreak(HeartBreakData data) {
        heartBreakConcurrentHashMap.remove(data);
    }

    public static synchronized LocalDateTime getNowTime() {
        return LocalDateTime.now();

    }

    // 开启线程不断循环检测
//    @PostConstruct
    @Scheduled(fixedRate = 30000)
    public void checkBreak() {
        LocalDateTime now = getNowTime();
        Enumeration<HeartBreakData> keys = heartBreakConcurrentHashMap.keys();
        while (keys.hasMoreElements()) { ///
            HeartBreakData data = keys.nextElement();
            LocalDateTime time = heartBreakConcurrentHashMap.get(data);
            Duration duration = Duration.between(now, time);
            String userName = data.getUserName();
            if (Math.abs(duration.toMinutes()) > 3) {
                robotNoHeartBreakMap.put(userName, "机器码为[" + data.getUuid() + "]通讯异常,请人工检查网络问题");
            }
        }
    }

    public String getHeartBreak(String userName) {
        if (robotNoHeartBreakMap.containsKey(userName)) {
            return robotNoHeartBreakMap.get(userName);
        }
        return "";
    }

    public void removeHeartBreak(String userName) {
        robotNoHeartBreakMap.remove(userName);
    }

    public String getMessage(List<String> userNames) {
        if (userNames != null && userNames.size() > 0) {
            List<String> exceptions = new ArrayList<>();
            userNames.forEach(userName -> {
                if (exceptionStrMap.containsKey(userName)) {
                    exceptions.add(exceptionStrMap.get(userName));
                }
            });
            return String.join(";", exceptions);
        }
        return "";
    }


    public void putMessage(ExceptionDto exceptionDto) {
        if (exceptionStrMap.containsKey(exceptionDto.getUserName())) {
            String mes = ";" + exceptionDto.getMessage();
            exceptionStrMap.put(exceptionDto.getUserName(), mes);
        } else {
            exceptionStrMap.put(exceptionDto.getUserName(), exceptionDto.getMessage());
        }
    }

    public void removeByUserName(List<String> userNames) {
        userNames.forEach(exceptionStrMap::remove);
    }

    public void alarm(AlarmNotice notice) {
        String[] phones = adminPhone.split("#");
        int type = notice.type;
        if (type == 0) {
            for (String phone : phones) {
                if (alarmNoticeMap1.containsKey(phone)) {
                    AlarmNotice record = alarmNoticeMap1.get(phone);
                    Duration duration = Duration.between(LocalDateTime.now(), record.getAlarmTime());
                    long hours = duration.toHours();//相差的小时数
                    if (Math.abs(hours) > 1) {
                        record.setAlarmTime(LocalDateTime.now());
                        SendSms.send(phone, notice.type);
                    }
                } else {
                    notice.setAlarmTime(LocalDateTime.now());
                    alarmNoticeMap1.put(phone, notice);
                    SendSms.send(phone, notice.type);
                }
            }
        } else if (type == 1) {
            for (String phone : phones) {
                if (alarmNoticeMap2.containsKey(phone)) {
                    AlarmNotice record = alarmNoticeMap2.get(phone);
                    Duration duration = Duration.between(LocalDateTime.now(), record.getAlarmTime());
                    long hours = duration.toHours();//相差的小时数
                    if (Math.abs(hours) > 1) {
                        record.setAlarmTime(LocalDateTime.now());
                        SendSms.send(phone, notice.type);
                    }
                } else {
                    notice.setAlarmTime(LocalDateTime.now());
                    alarmNoticeMap2.put(phone, notice);
                    SendSms.send(phone, notice.type);
                }
            }
        }

    }

    public List<BreakDto> getMessages() {
        Enumeration<HeartBreakData> keys = heartBreakConcurrentHashMap.keys();
        List<BreakDto> mesList = new ArrayList<>();
        while (keys.hasMoreElements()) {
            HeartBreakData data = keys.nextElement();
            LocalDateTime time = heartBreakConcurrentHashMap.get(data);
            BreakDto dto = new BreakDto();
            BeanUtils.copyProperties(data, dto);
            dto.setAlarmTime(time);
            mesList.add(dto);
        }
        return mesList;
    }

    public List<String> getErrorMessages() {
        Enumeration<String> keys = robotNoHeartBreakMap.keys();
        List<String> mesList = new ArrayList<>();
        while (keys.hasMoreElements()) {
            String data = keys.nextElement();
            mesList.add(data);
        }
        return mesList;
    }

    @Data
    public static class BreakDto implements Serializable {
        private String uuid;
        private String ip;
        private String userName; // 登录账号
        private LocalDateTime alarmTime;
    }

    @Data
    public static class AlarmNotice implements Serializable {
        private int type;    // 0代表验证码  1 代表流程
        private LocalDateTime alarmTime;
    }

}
